home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * TAPE-HANDLER.C
- *
- * tape interface
- *
- * TAPE:flags
- *
- * r rewind
- * a append
- */
-
- #include "defs.h"
-
- #define SwapBufs(chan) { char *t1 = chan->ch_Buf1; long l1 = chan->ch_BufLen1; \
- chan->ch_Buf1 = chan->ch_Buf2; chan->ch_BufLen1 = chan->ch_BufLen2; \
- chan->ch_Buf2 = t1; chan->ch_BufLen2 = l1; \
- }
-
- Prototype int main(short, char **);
- Prototype void myexit(void);
- Prototype void MkDevice(char *);
- Prototype void DelDevice(void);
- Prototype void *DosAllocMem(long);
- Prototype void DosFree(void *);
- Prototype void HandleDosPacket(DosPacket *, short);
- Prototype void HandleReturnedRequest(Chan *);
- Prototype void ReturnPacket(DosPacket *);
- Prototype void HoldPacket(List *, DosPacket *);
- Prototype void RetryWaitingPacket(List *);
-
- Prototype MsgPort *IoSink;
- Prototype MsgPort *DosRetry;
- Prototype short DDebug;
- Prototype List ChanList;
-
- MsgPort *IoSink;
- MsgPort *DosRetry;
- char *DeviceName = "scsi.device";
- long UnitNo = -1;
- short DDebug;
- List ChanList;
-
- ubyte rewind_cmd[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
- ubyte append_cmd[] = { 0x11, 0x03, 0x00, 0x00, 0x00, 0x00 };
- ubyte filemark_cmd[] = { 0x10, 0x00, 0x00, 0x00, 0x01, 0x00 };
-
- extern struct DosLibrary *DOSBase;
-
- main(ac, av)
- short ac;
- char *av[];
- {
- long sinkMask;
- long retryMask;
- long mask;
-
- NewList(&ChanList);
- if (ac == 1) {
- printf("tape-handler device_name [-D scsi.device] -U unit\n");
- exit(0);
- }
- IoSink = CreatePort(NULL, 0);
- DosRetry = CreatePort(NULL, 0);
-
- sinkMask = 1 << IoSink->mp_SigBit;
- retryMask = 1 << DosRetry->mp_SigBit;
-
- {
- short i;
- for (i = 2; i < ac; ++i) {
- char *ptr = av[i];
- if (*ptr != '-')
- continue;
- ptr += 2;
- switch(ptr[-1]) {
- case 'D':
- DeviceName = (*ptr) ? ptr : av[++i];
- break;
- case 'U':
- UnitNo = strtol((*ptr) ? ptr : av[++i], NULL, 0);
- break;
- }
- }
- }
- if (DeviceName == NULL || UnitNo == -1) {
- puts("run <nil: >nil: tape-handler <devname> -D<device> -U<unit>");
- exit(20);
- }
- MkDevice(av[1]);
-
- for (;;) {
- Message *msg;
-
- while (msg = GetMsg(DosRetry))
- HandleDosPacket((DosPacket *)msg->mn_Node.ln_Name, 1);
- while (msg = GetMsg(IoSink)) {
- if (msg->mn_Node.ln_Type = NT_MESSAGE)
- HandleDosPacket((DosPacket *)msg->mn_Node.ln_Name, 0);
- else
- HandleReturnedRequest((Chan *)msg->mn_Node.ln_Name);
- }
- mask = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | sinkMask | retryMask);
- if (mask & (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D)) {
- if (GetHead(&ChanList) == NULL)
- break;
- }
- }
- return(0);
- }
-
- void
- myexit()
- {
- void *z = NULL;
-
- DelDevice();
- if (IoSink) {
- DeletePort(IoSink);
- IoSink = z;
- }
- if (DosRetry) {
- DeletePort(DosRetry);
- DosRetry = z;
- }
- }
-
- void
- HandleDosPacket(pkt, retry)
- DosPacket *pkt;
- short retry;
- {
- if (retry == 0) {
- pkt->dp_Res1 = 0;
- pkt->dp_Res2 = 0;
- }
-
- switch(pkt->dp_Type) {
- case ACTION_FINDUPDATE: /* FileHandle,Lock,Name Bool */
- case ACTION_FINDINPUT: /* FileHandle,Lock,Name Bool */
- case ACTION_FINDOUTPUT: /* FileHandle,Lock,Name Bool */
- /*
- * attempt to open tape scsi device
- */
-
- {
- FileHandle *fh = (FileHandle *)BADDR(pkt->dp_Arg1);
- Chan *chan = AllocMem(sizeof(Chan), MEMF_PUBLIC | MEMF_CLEAR);
- int error;
-
- NewList(&chan->ch_PktList);
- {
- ubyte *ptr = (ubyte *)BADDR(pkt->dp_Arg3);
- int len;
-
- for (len = *ptr; len > 0; --len) {
- if (ptr[len] == ':')
- break;
- switch(ptr[len] | 0x20) {
- case 'a': /* append */
- chan->ch_Flags |= CHANF_APPEND | CHANF_REWIND;
- break;
- case 'r': /* rewind */
- chan->ch_Flags |= CHANF_REWIND;
- break;
- }
- }
- }
- chan->ch_DeviceName = DeviceName;
- chan->ch_UnitNo = UnitNo;
- chan->ch_BufSize = 32768;
- chan->ch_Buf1 = AllocMem(chan->ch_BufSize, MEMF_PUBLIC);
- chan->ch_Buf2 = AllocMem(chan->ch_BufSize, MEMF_PUBLIC);
-
- error = SCSIOpen(chan);
-
- if (error == 0 && chan->ch_Flags & CHANF_REWIND)
- error = DoSCSI(chan, rewind_cmd, NULL, 0, SCSIF_READ, NULL);
-
- if (error == 0 && chan->ch_Flags & CHANF_APPEND)
- error = DoSCSI(chan, append_cmd, NULL, 0, SCSIF_READ, NULL);
-
- if (error == 0) {
- fh->fh_Port = (MsgPort *)DOS_FALSE;
- fh->fh_Arg1 = chan;
- pkt->dp_Res1 = DOS_TRUE;
- pkt->dp_Res2 = 0;
- AddTail(&ChanList, &chan->ch_Node);
- } else {
- SCSIClose(chan);
- fh->fh_Port = (MsgPort *)DOS_FALSE;
- fh->fh_Arg1 = NULL;
- pkt->dp_Res2 = error;
- pkt->dp_Res1 = DOS_FALSE;
- FreeMem(chan->ch_Buf1, chan->ch_BufSize);
- FreeMem(chan->ch_Buf2, chan->ch_BufSize);
- FreeMem(chan, sizeof(Chan));
- }
- }
- ReturnPacket(pkt);
- break;
- case ACTION_READ: /* FHArg1,CPTRBuffer,Length ActLength */
- /*
- * read data
- */
-
- {
- Chan *chan = (Chan *)pkt->dp_Arg1;
- long n;
- long bytes = pkt->dp_Arg3 - pkt->dp_Res1;
-
-
- /*
- * copy from Buf1
- */
-
- if (n = chan->ch_BufLen1) {
- if (n > bytes)
- n = bytes;
- CopyMem(chan->ch_Buf1 + chan->ch_BufIdx1, (void *)((long)pkt->dp_Arg2 + pkt->dp_Res1), n);
- pkt->dp_Res1 += n;
- bytes -= n;
- chan->ch_BufLen1 -= n;
- chan->ch_BufIdx1 += n;
- }
-
- /*
- * return or requeue DOS request as indicated
- */
-
- if (bytes == 0 || (chan->ch_Flags & CHANF_EOF))
- ReturnPacket(pkt);
- else
- HoldPacket(&chan->ch_PktList, pkt);
-
- /*
- * if Buf1 empty and Buf2 not, move'm in
- */
-
- if (chan->ch_BufLen1 == 0 && chan->ch_BufLen2) {
- SwapBufs(chan);
- chan->ch_BufIdx1 = 0;
- RetryWaitingPacket(&chan->ch_PktList);
- }
-
- /*
- * attempt to read next buffer in while program processing
- * first. Or, if buffer is full, swap into buf1
- */
-
- if ((chan->ch_Flags & (CHANF_EOF|CHANF_IOSIP)) == 0 && chan->ch_BufLen2 == 0) {
- char read_cmd[6] = { 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 };
- SendSCSI(chan, read_cmd, chan->ch_Buf2, chan->ch_BufSize, SCSIF_READ);
- }
- }
- break;
- case ACTION_WRITE:
- /*
- * write data
- */
-
- {
- Chan *chan = (Chan *)pkt->dp_Arg1;
- long n;
- long bytes = pkt->dp_Arg3 - pkt->dp_Res1;
-
- /*
- * copy as much as possible to Buf1
- */
-
- chan->ch_Flags |= CHANF_WRITE;
- if (n = chan->ch_BufSize - chan->ch_BufLen1) {
- if (n > bytes)
- n = bytes;
- CopyMem((void *)((long)pkt->dp_Arg2 + pkt->dp_Res1), (void *)(chan->ch_Buf1 + chan->ch_BufLen1), n);
- pkt->dp_Res1 += n;
- bytes -= n;
- chan->ch_BufLen1 += n;
- }
-
- /*
- * return or requeue DOS request as indicated
- */
-
- if (bytes == 0 || (chan->ch_Flags & CHANF_EOF))
- ReturnPacket(pkt);
- else
- HoldPacket(&chan->ch_PktList, pkt);
-
- /*
- * If buffer is full then transfer to Buf2 and start write
- */
-
- if (chan->ch_BufLen1 == chan->ch_BufSize && chan->ch_BufLen2 == 0) {
- char write_cmd[6] = { 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00 };
- SendSCSI(chan, write_cmd, chan->ch_Buf1, chan->ch_BufLen1, SCSIF_WRITE);
- SwapBufs(chan);
- RetryWaitingPacket(&chan->ch_PktList);
- }
- }
- break;
- case ACTION_END:
- {
- Chan *chan = (Chan *)pkt->dp_Arg1;
-
- pkt->dp_Res2 = 0;
- pkt->dp_Res1 = DOS_TRUE;
- ReturnPacket(pkt);
-
- Remove(&chan->ch_Node);
- if (chan->ch_Flags & CHANF_WRITE) {
- char write_cmd[6] = { 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00 };
-
- if (chan->ch_Flags & CHANF_IOSIP)
- WaitSCSI(chan, NULL);
- if (chan->ch_BufLen1) {
- long extra = 512 - (chan->ch_BufLen1 & 511);
-
- if (extra == 512)
- extra = 0;
- if (extra)
- clrmem(chan->ch_Buf1 + chan->ch_BufLen1, extra);
- DoSCSI(chan, write_cmd, chan->ch_Buf1, chan->ch_BufLen1 + extra, SCSIF_WRITE, NULL);
- }
- DoSCSI(chan, filemark_cmd, NULL, 0, SCSIF_READ, NULL);
- }
- SCSIClose(chan);
- FreeMem(chan->ch_Buf1, chan->ch_BufSize);
- FreeMem(chan->ch_Buf2, chan->ch_BufSize);
- FreeMem(chan, sizeof(Chan));
- }
- break;
- case ACTION_DIE:
- default:
- pkt->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
- pkt->dp_Res1 = DOS_FALSE;
- ReturnPacket(pkt);
- break;
- }
- }
-
- void
- HandleReturnedRequest(chan)
- Chan *chan;
- {
- long len;
- int error;
-
- chan->ch_Flags &= ~CHANF_IOSIP;
- error = WaitSCSI(chan, &len);
-
- if (chan->ch_Flags & CHANF_WRITE) {
- /*
- * if write returned buffer space now freed up
- */
-
- chan->ch_BufLen2 = 0;
- RetryWaitingPacket(&chan->ch_PktList);
- } else {
- /*
- * if read returned, data now available and can queue up another
- * read, in fact!
- */
-
- switch(error) {
- case 0x80:
- chan->ch_Flags |= CHANF_EOF;
- /* fall through */
- case 0:
- break;
- default:
- len = 0;
- }
- chan->ch_BufLen2 = len;
-
- if (chan->ch_BufLen1 == 0 && chan->ch_BufLen2) {
- SwapBufs(chan);
- chan->ch_BufIdx1 = 0;
- RetryWaitingPacket(&chan->ch_PktList);
- }
- RetryWaitingPacket(&chan->ch_PktList);
- }
- }
-
- DosList *Dl;
-
- void
- MkDevice(devName)
- char *devName;
- {
- DosList *dl;
- RootNode *root;
- DosInfo *info;
-
- Dl = dl = (struct DosList *)DosAllocMem(sizeof(struct DosList)+strlen(devName)+2);
- strcpy((char *)(dl+1) + 1, devName);
- *(char *)(dl + 1) = strlen(devName);
- dl->dol_Type = DLT_DEVICE;
- dl->dol_Task = IoSink;
- dl->dol_Name = MKBADDR((char *)(dl+1));
-
- Forbid();
- root = (struct RootNode *)DOSBase->dl_Root;
- info = (struct DosInfo *)BADDR(root->rn_Info);
- dl->dol_Next = info->di_DevInfo;
- info->di_DevInfo = MKBADDR(dl);
- Permit();
- }
-
- void
- DelDevice()
- {
- DosList *dl;
- DosInfo *info;
- RootNode *root;
- DosList *dls;
- BPTR *bpp;
-
- if (dl = Dl) {
- Forbid();
- root = (struct RootNode *)DOSBase->dl_Root;
- info = (struct DosInfo *)BADDR(root->rn_Info);
-
- for (bpp = &info->di_DevInfo; dls = BADDR(*bpp); bpp = &dls->dol_Next) {
- if (dls == dl)
- break;
- }
- if (dls == dl) {
- *bpp = dls->dol_Next;
- } else {
- ;
- }
- Permit();
- DosFree(dl);
- Dl = NULL;
- }
- }
-
- void *
- DosAllocMem(bytes)
- long bytes;
- {
- long *ptr;
-
- bytes += 4;
-
- if (ptr = AllocMem(bytes, MEMF_PUBLIC | MEMF_CLEAR)) {
- *ptr++ = bytes;
- return((void *)ptr);
- }
- }
-
- void
- DosFree(vptr)
- void *vptr;
- {
- long *ptr = vptr;
- --ptr;
- FreeMem(ptr, *ptr);
- }
-
- void
- ReturnPacket(pkt)
- DosPacket *pkt;
- {
- Message *msg;
- MsgPort *replyPort;
-
- replyPort = pkt->dp_Port;
- msg = pkt->dp_Link;
- pkt->dp_Port = IoSink;
- msg->mn_Node.ln_Name = (char *)pkt;
- PutMsg(replyPort, msg);
- }
-
- void
- HoldPacket(list, pkt)
- List *list;
- DosPacket *pkt;
- {
- AddTail(list, &pkt->dp_Link->mn_Node);
- }
-
- void
- RetryWaitingPacket(list)
- List *list;
- {
- Message *msg;
-
- while (msg = RemHead(list))
- PutMsg(DosRetry, msg);
- }
-
-